
#include "RtBase.h"
#include "RtHttpUtilClasses.h"
#include "RtUtilClasses.h"

class /*RT_API_EXPORT*/ CRtAtomTablesFind
{
public:
	explicit CRtAtomTablesFind(const CRtHttpAtom &aAtom)
		: m_FindAtom(aAtom)
	{
	}
	bool operator() (const CRtHttpAtom &aAtom)
	{
		return strcasecmp(aAtom.get(), m_FindAtom.get()) ? false : true;
	}
private:
	const CRtHttpAtom &m_FindAtom;
};

///////////////////////////////////////////////////////////////
// class CRtHttpAtomList
///////////////////////////////////////////////////////////////

// define storage for all atoms
#define HTTP_ATOM(name, value) CRtHttpAtom CRtHttpAtomList::name(value);
#include "RtHttpAtomList.h"
#undef HTTP_ATOM

CRtHttpAtomList* CRtHttpAtomList::Instance()
{
	return CRtSingletonT<CRtHttpAtomList>::Instance();
}

CRtHttpAtomList::CRtHttpAtomList()
	: s_bAtomTableCreated(FALSE)
{
	RT_INFO_TRACE_THIS("CRtHttpAtomList::CRtHttpAtomList");
}

CRtHttpAtomList::~CRtHttpAtomList()
{
	if (!m_newAtoms.empty())
	{
		for (std::vector<char*>::iterator it=m_newAtoms.begin(); it!=m_newAtoms.end(); ++it)
		{
			delete *it;
		}
		m_newAtoms.clear();
	}
}

void CRtHttpAtomList::CreateAtomTable()
{
	if (s_bAtomTableCreated)
		return;

#define HTTP_ATOM(name, value) \
	s_AtomTables.insert(CRtHttpAtomList::name);
#include "RtHttpAtomList.h"
#undef HTTP_ATOM
	
	s_bAtomTableCreated = TRUE;
}

CRtHttpAtom CRtHttpAtomList::
ResolveAtom(const CRtString &aValue, BOOL bAdd)
{
	CRtHttpAtom atomFind;
	CRtString strValue(aValue);
	TrimString(strValue, CRtIsSpace());
	RT_ASSERTE_RETURN(!strValue.empty(), atomFind);

	if (!s_bAtomTableCreated) 
		CreateAtomTable();

	CRtMutexGuardT<MutexType> theGuard(m_mutex);
	
	atomFind = strValue.c_str();
	AtomTablesType::iterator iter = s_AtomTables.find(atomFind);
//	iter = std::find_if(s_AtomTables.begin(), s_AtomTables.end(), CRtAtomTablesFind(atomFind));
	if (iter != s_AtomTables.end())
		atomFind = *iter;
	else if (bAdd){
		// TODO: delete it when s_AtomTables is destoryed.
		LPSTR pNew = new char[strValue.length() + 1];
		if (pNew) {
			::strcpy(pNew, strValue.c_str());
			atomFind = pNew;
			s_AtomTables.insert(atomFind);
			m_newAtoms.push_back(pNew);
		}
	}
	return atomFind;
}


///////////////////////////////////////////////////////////////
// class CRtHttpProxyInfo
///////////////////////////////////////////////////////////////

CRtHttpProxyInfo::CRtHttpProxyInfo() 
	: m_wPort(0)
	, m_bFirstTryWithoutUserName(TRUE)
	, m_nType(HTTP_PROXY)
{
}

RtResult CRtHttpProxyInfo::Init(const CRtString &aHostAndPort, PROXY_TYPE aType)
{
	CRtString strObj;
	WORD wPort = 0;
	CRtString::size_type nFind = aHostAndPort.find(':', 0);
	if (nFind == CRtString::npos) {
		strObj = aHostAndPort;
	} else {
		strObj = aHostAndPort.substr(0, nFind);
		CRtString strPort = aHostAndPort.substr(nFind + 1);
		wPort = atoi(strPort.c_str());
	}
	return Init(strObj, wPort, aType);
}

RtResult CRtHttpProxyInfo::Init(const CRtString &aHost, WORD aPort, PROXY_TYPE aType)
{
	CRtString strObj(aHost);
	TrimString(strObj, CRtIsSpace());
	m_strHostName = strObj;
	if (m_strHostName.empty())
		return RT_ERROR_INVALID_ARG;
	
	m_nType = aType;
	m_wPort = aPort;
	if (m_wPort <= 0)
		m_wPort = (m_nType <= HTTPS_PROXY) ? 80 : 1080;
	m_strAuthScheme.resize(0);
	return RT_OK;
}

BOOL CRtHttpProxyInfo::Equal(const CRtHttpProxyInfo& aRight)
{
	return (this == &aRight || 
		(m_strHostName == aRight.m_strHostName && m_wPort == aRight.m_wPort));
}
